﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;

public class ZUIAnimTools : MonoBehaviour {

    public AnimationCurve curve = AnimationCurve.EaseInOut(0,0,1,1); 
    public enum EaseType
    {
        Curve,//使用曲线
        Line,
        OutSine,//先快后慢
    }
    
    private DoActionDelay _mDoActionDelay;
    public DoActionDelay DoActionDelay
    {
        get
        {
            if (_mDoActionDelay == null)
            {
                _mDoActionDelay = gameObject.AddComponent<DoActionDelay>();
            }
            return _mDoActionDelay;
        }
    }
    public void InitCurve(AnimationCurve _curve)
    {
        curve = _curve;
    }

    public Coroutine RectMove(RectTransform rect, Vector2 targetPos, float time)
    {
        if (!this)
            return null;

        return StartCoroutine(PlayRectMove(rect, targetPos, time,  EaseType.Curve));
    }
    public Coroutine RectMove(RectTransform rect, Vector2 targetPos, float time, Action callback, EaseType easeType)
    {
        if (!this)
            return null;

        DoActionDelay.DelayDoAction(time,callback);
        return StartCoroutine(PlayRectMove(rect, targetPos, time,  easeType));
    }
    
    /// <summary>
    /// UI移动
    /// </summary>
    /// <param name="rect"></param>
    /// <param name="targetPos"></param>
    /// <param name="time"></param>
    /// <param name="callback"></param>
    /// <returns></returns>
    IEnumerator PlayRectMove(RectTransform rect, Vector2 targetPos, float time,  EaseType easeType)
    {
        float timer = 0;
        Vector2 originalPos = rect.anchoredPosition;
        while (timer <= time)
        {
            timer += Time.deltaTime;

            float rate = timer / time;
            float y = OnSineEvaluate(rate);
            switch (easeType)
            {
                case EaseType.Line: y = OnLineEvaluate(rate); break;
                case EaseType.OutSine: y = OnSineEvaluate(rate); break;
                case EaseType.Curve:y = curve.Evaluate(rate);break;
            }
            rect.anchoredPosition = originalPos + (targetPos - originalPos) * y;
            yield return null;
        }
        rect.anchoredPosition = targetPos;
    }
    public Coroutine UIAlpha(RectTransform imgTxt, float targetAlpha, float time)
    {
        return UIAlpha(imgTxt, targetAlpha, time, null, EaseType.Curve,null);
    }
    public Coroutine UIAlpha(RectTransform imgTxt, float targetAlpha, float time, Action callback)
    {
        return UIAlpha(imgTxt, targetAlpha, time, callback, EaseType.Curve,null);
    }
    public Coroutine UIAlpha(RectTransform imgTxt, float targetAlpha, float time, Action callback, EaseType easeType)
    {
        return UIAlpha(imgTxt, targetAlpha, time, callback, easeType, null);
    }
    public Coroutine UIAlpha(RectTransform imgTxt, float targetAlpha, float time, Action callback , EaseType easeType,Action<Color,RectTransform>setColorAction )
    {
        if (!this)
        {
            if (callback != null)
                callback();
            return null;
        }

        if (imgTxt == null)
        {
            Debug.LogError("imgTxt == null!");
            
            if (callback != null)
                callback();
            return null;
        }

        List<float> imgTargetAlpha = new List<float>();
        List<float> txtTargetAlpha = new List<float>();
        List<float> rawImgTargetAlpha = new List<float>();
        List<float> tmptxtTargetAlpha = new List<float>();

        var imagesList = imgTxt.GetComponentsInChildren<Image>(true);
        var textsList = imgTxt.GetComponentsInChildren<Text>(true);
        var rawImagesList = imgTxt.GetComponentsInChildren<RawImage>(true);
        var tmptxtList = imgTxt.GetComponentsInChildren<TMPro.TextMeshProUGUI>(true);

        for (int i = 0; i < imagesList.Length; i++)
        {
            imgTargetAlpha.Add(targetAlpha);
        }
        for (int i = 0; i < textsList.Length; i++)
        {
            txtTargetAlpha.Add(targetAlpha);
        }
        for (int i = 0; i < rawImagesList.Length; i++)
        {
            rawImgTargetAlpha.Add(targetAlpha);
        }
        for (int i = 0; i < tmptxtList.Length; i++)
        {
            tmptxtTargetAlpha.Add(targetAlpha);
        }
        if (!gameObject.activeInHierarchy)
        {
            if (callback != null)
                callback();
            Debug.LogError("!gameObject.activeInHierarchy");
            return null;
        }

        this.DoActionDelay.DelayDoAction(time,callback);
        return StartCoroutine(PlayUIAlpha(imgTxt, imgTargetAlpha, txtTargetAlpha, rawImgTargetAlpha, tmptxtTargetAlpha,time,  easeType, setColorAction));
    }

    public Coroutine UIAlpha(RectTransform imgTxt, List<float> imgTargetAlpha, List<float> txtTargetAlpha, List<float> rawImgtxtTargetAlpha,List<float> tmptxtTargetAlpha, float time)
    {
        return UIAlpha(imgTxt, imgTargetAlpha, txtTargetAlpha, rawImgtxtTargetAlpha,tmptxtTargetAlpha, time, null, EaseType.Curve,null);
    }
    public Coroutine UIAlpha(RectTransform imgTxt, List<float> imgTargetAlpha, List<float> txtTargetAlpha, List<float> rawImgtxtTargetAlpha,List<float> tmptxtTargetAlpha, float time, Action callback)
    {
        return UIAlpha(imgTxt, imgTargetAlpha, txtTargetAlpha, rawImgtxtTargetAlpha,tmptxtTargetAlpha,  time, callback, EaseType.Curve, null);
    }
    public Coroutine UIAlpha(RectTransform imgTxt, List<float> imgTargetAlpha, List<float> txtTargetAlpha, List<float> rawImgtxtTargetAlpha,List<float> tmptxtTargetAlpha, float time, Action callback, EaseType easeType)
    {
        return UIAlpha(imgTxt, imgTargetAlpha, txtTargetAlpha, rawImgtxtTargetAlpha,tmptxtTargetAlpha,  time, callback, easeType, null);
    }
    public Coroutine UIAlpha(RectTransform imgTxt, List<float> imgTargetAlpha, List<float> txtTargetAlpha, List<float> rawImgtxtTargetAlpha,List<float> tmptxtTargetAlpha, float time, Action callback, EaseType easeType,Action<Color,RectTransform>setColorAction)
    {
        if (!this)
        {
            if (callback != null)
                callback();
            return null;
        }

        if (imgTxt == null)
        {
            if (callback != null)
                callback();
            return null;
        }
        this.DoActionDelay.DelayDoAction(time,callback);
        return StartCoroutine(PlayUIAlpha(imgTxt, imgTargetAlpha, txtTargetAlpha, rawImgtxtTargetAlpha, tmptxtTargetAlpha,time,  easeType, setColorAction));
    }

    public static void GetImgTxtAlpha(RectTransform imgTxt, out List<float> imgAlpha, out List<float> txtAlpha, out List<float> rawAlpha, out List<float> tmptxtAlpha)
    {
        imgAlpha = new List<float>();
        txtAlpha = new List<float>();
        rawAlpha = new List<float>();
        tmptxtAlpha = new List<float>();
        
        var imagesList = imgTxt.GetComponentsInChildren<Image>(true);
        foreach (var img in imagesList)
        {
            imgAlpha.Add(img.color.a);
        }
        var textsList = imgTxt.GetComponentsInChildren<Text>(true);
        foreach (var txt in textsList)
        {
            txtAlpha.Add(txt.color.a);
        }
        var rawImgsList = imgTxt.GetComponentsInChildren<RawImage>(true);
        foreach (var img in rawImgsList)
        {
            rawAlpha.Add(img.color.a);
        }
        foreach (var img in imgTxt.GetComponentsInChildren<TMPro.TextMeshProUGUI>(true))
        {
            tmptxtAlpha.Add(img.color.a);
        }
    }
    public static void GetImgTxtOringinalColor(RectTransform imgTxt, out List<Color> imgOringinalColors, out List<Color> txtOringinalColors)
    {
        GetImgTxtOringinalColor(imgTxt,out imgOringinalColors,out txtOringinalColors,out List<Color> c,out List<Color> t);
    }
    public static void GetImgTxtOringinalColor(RectTransform imgTxt, out List<Color> imgOringinalColors, out List<Color> txtOringinalColors, out List<Color> rawOringinalColors, out List<Color> tmptxtOringinalColors)
    {
        imgOringinalColors = new List<Color>();
        txtOringinalColors = new List<Color>();
        rawOringinalColors = new List<Color>();
        tmptxtOringinalColors = new List<Color>();
        
        foreach (var img in imgTxt.GetComponentsInChildren<Image>(true))
        {
            imgOringinalColors.Add(img.color);
        }
        foreach (var txt in imgTxt.GetComponentsInChildren<Text>(true))
        {
            txtOringinalColors.Add(txt.color);
        }
        foreach (var img in imgTxt.GetComponentsInChildren<RawImage>(true))
        {
            rawOringinalColors.Add(img.color);
        } 
        foreach (var img in imgTxt.GetComponentsInChildren<TMPro.TextMeshProUGUI>(true))
        {
            tmptxtOringinalColors.Add(img.color);
        }
    }


    IEnumerator PlayUIAlpha(RectTransform imgTxt,List<float> imgTargetAlpha, List<float> txtTargetAlpha, List<float> rawImgTargetAlpha, List<float> tmptxtTargetAlpha,float time, EaseType easeType,Action<Color, RectTransform> setColor)
    {
        if (imgTargetAlpha == null) imgTargetAlpha = new List<float>();
        if (txtTargetAlpha == null) txtTargetAlpha = new List<float>();
        if (rawImgTargetAlpha == null) rawImgTargetAlpha = new List<float>();
        if (tmptxtTargetAlpha == null) tmptxtTargetAlpha = new List<float>();

        if (imgTargetAlpha.Count <= 0 && txtTargetAlpha.Count <= 0 && rawImgTargetAlpha.Count <= 0 && tmptxtTargetAlpha.Count <= 0)
        {
            yield break;
        }

        float defaultTargetAlpha = imgTargetAlpha.Count>0? imgTargetAlpha[0]: txtTargetAlpha.Count > 0?txtTargetAlpha[0]: txtTargetAlpha.Count > 0?txtTargetAlpha[0]:rawImgTargetAlpha[0];

        List <Color> imageOringinalColorList = new List<Color>();
        List<Color> textOringinalColorList = new List<Color>();
        List<Color> rawImageOringinalColorList = new List<Color>();
        List<Color> tmptxtOringinalColorList = new List<Color>();
        var imagesList = imgTxt.GetComponentsInChildren<Image>(true);
        var textsList = imgTxt.GetComponentsInChildren<Text>(true);
        var rawImagesList = imgTxt.GetComponentsInChildren<RawImage>(true);
        var tmptxtList = imgTxt.GetComponentsInChildren<TMPro.TextMeshProUGUI>(true);

        if (imagesList.Length == 0
            && textsList.Length == 0
            && rawImagesList.Length == 0
            && tmptxtList.Length == 0)
        {
            yield break;
        }

        GetImgTxtOringinalColor(imgTxt,out imageOringinalColorList,out textOringinalColorList,out rawImageOringinalColorList,out tmptxtOringinalColorList);
       // yield return null;
        float timer = 0;
        while (timer <= time)
        {
            yield return null;
            timer += Time.deltaTime;

            float rate = timer / time;
            float y = OnSineEvaluate(rate);
            switch (easeType)
            {
                case EaseType.Line: y = OnLineEvaluate(rate); break;
                case EaseType.OutSine: y = OnSineEvaluate(rate); break;
                case EaseType.Curve: y = curve.Evaluate(rate ); break;
            }

            for (int i = 0; i < imagesList.Length; i++)
            {
                if (imagesList[i] == null)continue;

                var imgColor = imagesList[i].color;

                float targetAlpha = i < imgTargetAlpha.Count ? imgTargetAlpha[i] : defaultTargetAlpha;

                float imgCurA = Mathf.Lerp(imageOringinalColorList[i].a, targetAlpha,y); 

                imgColor.a = imgCurA;
                imagesList[i].color = imgColor;

                setColor?.Invoke(imgColor, imagesList[i].rectTransform);
            }
            for (int i = 0; i < textsList.Length; i++)
            {
                if (textsList[i] == null) continue;

                var txtColor = textsList[i].color;

                float targetAlpha = i < txtTargetAlpha.Count ? txtTargetAlpha[i] : defaultTargetAlpha;

                float txtCurA = Mathf.Lerp(textOringinalColorList[i].a, targetAlpha, y);

                txtColor.a = txtCurA;
                textsList[i].color = txtColor;

                setColor?.Invoke(txtColor, textsList[i].rectTransform);
            }
            for (int i = 0; i < rawImagesList.Length; i++)
            {
                if (rawImagesList[i] == null) continue;

                var imgColor = rawImagesList[i].color;

                float targetAlpha = i < rawImgTargetAlpha.Count ? rawImgTargetAlpha[i] : defaultTargetAlpha;

                float rawCurA = Mathf.Lerp(rawImageOringinalColorList[i].a, targetAlpha, y);

                imgColor.a = rawCurA;
                rawImagesList[i].color = imgColor;

                setColor?.Invoke(imgColor, rawImagesList[i].rectTransform);
            }
            for (int i = 0; i < tmptxtList.Length; i++)
            {
                if (tmptxtList[i] == null) continue;

                var txtColor = tmptxtList[i].color;

                float targetAlpha = i < tmptxtTargetAlpha.Count ? tmptxtTargetAlpha[i] : defaultTargetAlpha;

                float txtCurA = Mathf.Lerp(tmptxtOringinalColorList[i].a, targetAlpha, y);

                txtColor.a = txtCurA;
                tmptxtList[i].color = txtColor;

                setColor?.Invoke(txtColor, tmptxtList[i].rectTransform);
            }
        }
    }

    public  void SetImgTxtAlpha(RectTransform imgTxt,float targetAlpha)
    {
        if (imgTxt == null)
            return;

        var imagesList = imgTxt.GetComponentsInChildren<Image>(true);
        var textsList = imgTxt.GetComponentsInChildren<Text>(true);
        var rawImagesList = imgTxt.GetComponentsInChildren<RawImage>(true);


        for (int i = 0; i < imagesList.Length; i++)
        {
            Color iColor = imagesList[i].color;
            iColor.a = targetAlpha;
            imagesList[i].color = iColor;
        }
        for (int i = 0; i < rawImagesList.Length; i++)
        {
            Color iColor = rawImagesList[i].color;
            iColor.a = targetAlpha;
            rawImagesList[i].color = iColor;
        }
        for (int i = 0; i < textsList.Length; i++)
        {
            Color tColor = textsList[i].color;
            tColor.a = targetAlpha;
            textsList[i].color = tColor;
        }
    }

    public Coroutine UIColor(RectTransform imgTxt,Color color, float time)
    {
        return UIColor(imgTxt, color, time, null, EaseType.Line,true);
    }

    public Coroutine UIColor(RectTransform imgTxt, Color color, float time, Action callback, EaseType easeType,bool includeChild)
    {
        if (!this)
        {
            return null;
        }

        if (imgTxt == null)
        {
            if (callback != null)
                callback();
            return null;
        }

        return StartCoroutine(PlayUIColor(imgTxt, color, time, callback, easeType, includeChild));
    }
    IEnumerator PlayUIColor(RectTransform imgTxt, Color targetColor, float time, Action callback, EaseType easeType,bool includeChild)
    {
        List<Color> imageOringinalColorList = new List<Color>();
        List<Color> textOringinalColorList = new List<Color>();
        Image[] imagesList = new Image[0];
        Text[] textsList = new Text[0];

        if (includeChild)
        {
            imgTxt.GetComponentsInChildren<Image>(true);
            textsList = imgTxt.GetComponentsInChildren<Text>(true);
        }
        else
        {
            var img = imgTxt.GetComponent<Image>();
            if (img != null)
                imagesList = new Image[1] { img };

            var txt = imgTxt.GetComponent<Text>();
            if (txt != null)
                textsList = new Text[1] { txt };
        }
        if (imagesList.Length == 0
            && textsList.Length == 0)
        {
            if (callback != null)
                callback();
            yield break;
        }

        GetImgTxtOringinalColor(imgTxt, out imageOringinalColorList, out textOringinalColorList);

        float timer = 0;
        while (timer <= time)
        {
            yield return null;
            timer += Time.deltaTime;

            float rate = timer / time;
            float y = OnSineEvaluate(rate);
            switch (easeType)
            {
                case EaseType.Line: y = OnLineEvaluate(rate); break;
                case EaseType.OutSine: y = OnSineEvaluate(rate); break;
                case EaseType.Curve: y = curve.Evaluate(rate); break;
            }

            for (int i = 0; i < imagesList.Length; i++)
            {
                if (imagesList[i] == null) continue;

                var imgColor = imagesList[i].color;

                Color curColor = Color.Lerp(imgColor, targetColor, y);

                imagesList[i].color = curColor;
            }
            for (int i = 0; i < textsList.Length; i++)
            {
                if (textsList[i] == null) continue;

                var txtColor = textsList[i].color;

                Color curColor = Color.Lerp(txtColor, targetColor, y);

                imagesList[i].color = curColor;
            }

        }
    
        SetImgTxtListColor(imagesList, textsList, targetColor);

        if (callback != null)
            callback();
    }

    public void SetImgTxtColor(RectTransform imgTxt, Color targetColor,bool includeChild)
    {
        if (imgTxt == null)
            return;

        var imagesList = imgTxt.GetComponentsInChildren<Image>(true);
        var textsList = imgTxt.GetComponentsInChildren<Text>(true);

        SetImgTxtListColor(imagesList, textsList, targetColor);
    }

    void SetImgTxtListColor(Image[] imagesList, Text[] textsList, Color targetColor)
    {
        for (int i = 0; i < imagesList.Length; i++)
        {
            imagesList[i].color = targetColor;
        }
        for (int i = 0; i < textsList.Length; i++)
        {
            textsList[i].color = targetColor;
        }
    }


    static float OnLineEvaluate(float x)
    {
        return x;
    }

    static float OnSineEvaluate(float x)
    {
        x = Mathf.Clamp01(x); 

        var y = Mathf.Sin(x * Mathf.PI / 2);
        //DYDebug.Log("y:" + y);
        return y;
    }

    public void StopAllAnim()
    {
        if(this)
            StopAllCoroutines();
    }

}
